package com.meanbean.studytime.controls;

import java.io.IOException;
import java.util.LinkedList;

import com.meanbean.studytime.StudyTimeFile;
import com.meanbean.studytime.StudyTimeMain;
import com.meanbean.studytime.StudyTimeStage;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.effect.GaussianBlur;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;

/**
 * Controller for the StudyControl.fxml.
 * @author Derek Webb
 */
public class StudyControl extends AnchorPane
{
	@FXML private Pane buttonAddPane;
	@FXML private ImageView imageView;
	
	private StudyTimeFile studyTimeFile;
	
	private boolean mouseDidDrag = false;
	
	/**
	 * Creates a StudyControl object.
	 */
	public StudyControl()
	{
		FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("StudyControl.fxml"));
		fxmlLoader.setRoot(this);
		fxmlLoader.setController(this);
		
		try
		{
			fxmlLoader.load();
		}
		catch (IOException e)
		{
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * When a drag is detected, the event will be handled by this method.
	 * This will set a flag letting this object know that a drag has occured.
	 * @param event The MouseEvent.
	 */
	@FXML
	private void mouseDragged(MouseEvent event)
	{
		mouseDidDrag = true;
	}
	
	/**
	 * If in edit mode and the left mouse button is clicked, this event will add a button to the screen.
	 * @param event The MouseEvent.
	 */
	@FXML
	private void mouseClicked(MouseEvent event)
	{
		// Do not do anything if a drag is detected.  We do not want to place
		// a button after a drag.  We only place a button if a click has occured (with no drag).
		if (!mouseDidDrag)
		{
			if (StudyTimeStage.getMode() == StudyTimeStage.Mode.Edit)
			{
				if (event.getButton() == MouseButton.PRIMARY)
				{
					int buttonAddOffset = 5;
					
					// Create the EditButton
					EditButton editButton = new EditButton((int)event.getX() - buttonAddOffset, (int)event.getY() - buttonAddOffset, "");
					
					// Add the EditButton
					buttonAddPane.getChildren().add(editButton);
					
					// Add the associated TextField
					buttonAddPane.getChildren().add(editButton.getTextField());
					
					// Since we are in edit mode, open the button for editing
					editButton.open();
				}
			}
		}
		
		// Set the mouseDragged back to false
		mouseDidDrag = false;
	}
	
	/**
	 * Notifies that the program mode has changed and that the buttons
	 * should be updated (to either StudyButtons or EditButtons).
	 */
	public void modeChanged()
	{
		// If we are switching from Edit mode, then we need to save our new buttons
		if (StudyTimeStage.getMode() == StudyTimeStage.Mode.Study)
			saveButtons();
		
		removeStudyTimeButtons();
		
		// Load the buttons
		loadButtons(studyTimeFile);
	}
	
	/**
	 * Loads and displays an image (jpg).
	 * @param studyTimeFile The file path to the image (jpg) to be displayed.
	 */
	public void openNewSTF(StudyTimeFile studyTimeFile)
	{
		StudyTimeStage.setMode(StudyTimeStage.Mode.Edit);
		
		this.studyTimeFile = studyTimeFile;
		
		removeStudyTimeButtons();
		
		loadImage(studyTimeFile);
	}
	
	/**
	 * Loads and displays the image and StudyTimeButtons from the stf.
	 * @param studyTimeFile The file path to the stf.
	 */
	public void openSTF(StudyTimeFile studyTimeFile)
	{
		StudyTimeStage.setMode(StudyTimeStage.Mode.Study);
		
		this.studyTimeFile = studyTimeFile;
		
		removeStudyTimeButtons();
		
		loadImage(studyTimeFile);
		loadButtons(studyTimeFile);
	}
	
	/**
	 * Loads the image, then uses a GaussianBlur on the Pane embedded in the ScrollPane.  This will
	 * run the GaussianBlur radius amount from 63 down to 0 in a short amount of time.
	 * This produces a "cool" look as the image goes from blurry to sharp.
	 * @param studyTimeFile The StudyTimeFile to load the image from.
	 */
	private void loadImage(StudyTimeFile studyTimeFile)
	{
		Image image = studyTimeFile.getImage();
		
		imageView.setImage(image);
		imageView.setFitWidth(image.getWidth());
		imageView.setFitHeight(image.getHeight());
		
		new Thread(new Runnable(){
			@Override
			public void run()
			{
				synchronized (this) 
				{
					double blurAmount = 63.0;
					
					GaussianBlur g = new GaussianBlur(blurAmount);
					
					buttonAddPane.setEffect(g);
					
					while (blurAmount >= 0)
					{
						blurAmount -= 1;
						g.setRadius(blurAmount);
						
						try
						{
							wait(10);
						} catch (InterruptedException e)
						{
							// TODO: Add log entry here
							e.printStackTrace();
						}
					}
					
					// Ensure that the GaussianBlur is back to zero
					g.setRadius(0);
				}
			}
		}).start();
	}
	
	/**
	 * Saves the current buttons in the StudyTimeFile.
	 */
	public void saveButtons()
	{
		if (studyTimeFile != null)
		{
			// Get the list of buttons.
			LinkedList<Button> buttonList = new LinkedList<Button>();
			
			// Save the current buttons in the list
			for (Node node : buttonAddPane.getChildren())
			{
				if (node instanceof Button)
				{
					// Ensure that the current answer is saved
					((Button)node).saveCurrentAnswer();
					
					// Add this button to the button list
					buttonList.add((Button) node);
				}
			}
			
			// Store this button list in the StudyTimeFile
			studyTimeFile.setButtonList(buttonList);
		}
	}
	
	/**
	 * Reloads the Buttons.
	 */
	public void reloadButtons()
	{
		// Remove the buttons
		removeStudyTimeButtons();
		
		// Load the buttons
		loadButtons(studyTimeFile);
	}
	
	/**
	 * Loads the Buttons from the StudyTimeFile and displays them on the StudyControl.
	 * This will load either StudyButtons, if in study mode, or EditButtons, if in edit mode.
	 * @param studyTimeFile The StudyTimeFile to load the StudyTimeButtonsFrom.
	 */
	private void loadButtons(StudyTimeFile studyTimeFile)
	{
		if (studyTimeFile != null)
		{
			LinkedList<Button> studyTimeButtons = studyTimeFile.getButtonList();
			
			for (Button button : studyTimeButtons)
			{
				if (StudyTimeStage.getMode() == StudyTimeStage.Mode.Study)
				{
					// Create a StudyButton copy of this Button
					StudyButton studyButton = button.copyAsStudyButton();
					
					// Add the button
					buttonAddPane.getChildren().add(studyButton);
					
					// Add the TextField associated with the button
					buttonAddPane.getChildren().add(studyButton.getTextField());
				}
				else if (StudyTimeStage.getMode() == StudyTimeStage.Mode.Edit)
				{
					// Create an EditButton copy of this Button
					EditButton editButton = button.copyAsEditButton();
					
					// Add the button
					buttonAddPane.getChildren().add(editButton);
					
					// Add the TextField associated with the button
					buttonAddPane.getChildren().add(editButton.getTextField());
				}
			}
		}
	}
	
	/**
	 * Removes a specific button.
	 * @param button The button to remove.
	 */
	public void removeButton(Button button)
	{
		// Remove the TextField
		buttonAddPane.getChildren().remove(button.getTextField());
		
		// Remove the Button
		buttonAddPane.getChildren().remove(button);
	}
	
	/**
	 * Removes the currently displaying StudyTimeButtons.
	 */
	private void removeStudyTimeButtons()
	{
		// Remove all of the children
		buttonAddPane.getChildren().clear();
		
		// Re-add the ImageView
		buttonAddPane.getChildren().add(imageView);
	}
	
	/**
	 * @return A Boolean representing whether or not the loaded STF file needs to be saved.
	 */
	public boolean needsToSaveSTF()
	{
		if (studyTimeFile != null)
			return studyTimeFile.needsToSave();
		else
			return false;
	}
	
	public void saveSTF() throws Exception
	{
		if (studyTimeFile != null)
			studyTimeFile.save();
		else
		{
			Dialog dialog = new Dialog("Error", "You cannot save...nothing... :)");
			dialog.initOwner(StudyTimeMain.studyTimeStage);
			dialog.show();
		}
	}
	
	public void saveSTFas() throws Exception
	{
		if (studyTimeFile != null)
			studyTimeFile.saveAs();
		else
		{
			Dialog dialog = new Dialog("Error", "You cannot save...nothing... :)");
			dialog.initOwner(StudyTimeMain.studyTimeStage);
			dialog.show();
		}
	}
}
